﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Framework.Core.Collections;
using Framework.Core.Dependency.Adapter;
using Framework.Core.Dependency.Domain;
using log4net;

namespace Framework.Core.Dependency.Parser
{
    internal class SourceParser : IDirectoryParser<Solution>
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(SourceParser));
        private readonly IDirectoryReader directoryReader;
        private readonly IStreamParser<Solution> solutionParser;
        private readonly IStreamReader streamReader;
        private readonly IStreamParser<Solution> vb6ProjectParser;

        private SourceParser(IDirectoryReader directoryReader,
                             IStreamReader streamReader,
                             IStreamParser<Solution> vb6ProjectParser,
                             IStreamParser<Solution> solutionParser)
        {
            this.directoryReader = directoryReader;
            this.streamReader = streamReader;
            this.vb6ProjectParser = vb6ProjectParser;
            this.solutionParser = solutionParser;
        }

        public SourceParser()
            : this(new DirectoryReader(), new StreamReader(), new Vb6ProjectParser(), new SolutionParser())
        {
        }

        public IEnumerable<Solution> Parse(string root, string branch)
        {
            var files = directoryReader.GetFiles(root);

            var result = new ConcurrentList<Solution>();

            Parallel.ForEach(
                files,
                file =>
                {
                    if (IsSln(file))
                    {
                        AddParsingSolutionResult(root, solutionParser, file, result);
                    }
                    if (IsVb6(file))
                    {
                        AddParsingSolutionResult(root, vb6ProjectParser, file, result);
                    }
                });
            return result;
        }

        private void AddParsingSolutionResult(string branch,
                                              IStreamParser<Solution> streamParser,
                                              string file,
                                              ICollection<Solution> result)
        {
            var solution = Parse(streamParser, file, branch);
            result.Add(solution);
        }

        private static bool IsSln(string file)
        {
            return file.EndsWith(".sln", StringComparison.InvariantCultureIgnoreCase);
        }

        private static bool IsVb6(string file)
        {
            return file.EndsWith(".vbp", StringComparison.InvariantCultureIgnoreCase);
        }

        private T Parse<T>(IStreamParser<T> parser, string file, string branch)
        {
            Logger.InfoFormat("Parsing {0} file", file);
            using (var fileStream = streamReader.GetStream(file))
            {
                return parser.Parse(fileStream, file, branch);
            }
        }
    }
}